/**
 * @file JLog.h
 * @brief 
 * 
 *      json格式的log，为了能够更好地和客户端通信，同时rule的配置更加直观。
 *      设计为全是静态成员
 * 
 *      同时也展示了runInLoop对事件的底层封装过程
 * 
 * @author Zyan (zyishere2001@qq.com)
 * @version 1.0
 * @date 2022-05-09
 * 
 * @copyright Copyright (c) 2022  Zyanishere2001
 * 
 * @par 修改日志:
 * 
 */
#ifndef _JLOG
#define _JLOG

#include "hlog.h"
#include "hfile.h"
#include <iostream>
#include <fstream>
#include "json.hpp"
#include <iomanip>


using namespace nlohmann;
using namespace hv;


//定义数据类，to serialize , to pharse
namespace Custom {
	struct HostInfo {
		std::string ip;
		UINT port;
	};
	struct PacketInfo {
		UCHAR protocol;
		HostInfo src;
		HostInfo dst;
		size_t len;
		bool causion;//是否需要注意
	};
	NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(HostInfo, ip, port)
	NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(PacketInfo, protocol, src, dst, len, causion);
	
	struct Err {
		std::string Time;
		std::string err;
		std::string suggestion;
	};
	NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Err, Time, err, suggestion);

	struct Log {
		std::string Time;
		std::string type;
		std::string from;
		std::string msg;
	};
	NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Log, Time,type, from, msg);

};

//json log，全是静态成员

class JLog{
public:
    static void init(){
        // errlog.open("./logs/err.json");//追加模式
        // if(errlog.is_open()){
        //     printf("---- open err.json ----\n");
        // }else{
        //     printf("---- open err.json failed----\n");
        // }
    }

    static void close(){
        errlog.close();
    }
    
    //展示runInloop是如何对event进行封装的
    static void ERR(hloop_t* loop,std::string err, std::string suggesstion = "WOO") {
        //数据类
        Custom::Err e{
            getTime(),
            err,
            suggesstion,
        };

        //To json
        json ej = e;
        auto ejVector = json::to_bson(ej);//二进制

        // vector在函数结束时会被回收，因此要复制一份；
        //拷贝构造函数（应该是深拷贝）
        auto copy = new std::vector<uint8_t>(ejVector);


        //事件的封装过程
        hevent_t ev; //事件结构体
        memset(&ev, 0, sizeof(ev));
        ev.event_type = HEVENT_TYPE_CUSTOM ; //自定义事件
        ev.priority = HEVENT_LOWEST_PRIORITY; //最低优先级
        ev.cb = JLog::writeLog ;//回调函数
        ev.userdata = copy;//应用数据

        hloop_post_event(loop,&ev);//添加事件

	}


    static void LOG(hloop_t* loop,std::string type, std::string from, std::string msg) {
		//实例化log数据类
        Custom::Log log{
            getTime(),type, from, msg
        };
        
        //To json
        json ej = log;
        auto ejVector = json::to_bson(ej);//to二进制

        //ejVector在函数结束时会被回收，因此要复制一份
        auto copy = new std::vector<uint8_t>(ejVector);

        //事件的封装过程
        hevent_t ev; //事件结构体
        memset(&ev, 0, sizeof(ev));

        ev.event_type = HEVENT_TYPE_CUSTOM ; //自定义事件
        ev.priority = HEVENT_LOWEST_PRIORITY; //最低优先级
        ev.cb = JLog::writeLog ;//回调函数
        ev.userdata = copy;//用户数据

        hloop_post_event(loop,&ev);//添加事件

	}

    static std::string getTime() {
		time_t now = time(0);
		char* dt = ctime(&now);
		return std::string(dt);
	}


private:

    static void writeLog(hevent_t* ev){
        errlog.open("./logs/err.json",std::ios::app);//追加模式
        if(errlog.is_open()){
            printf("---- open err.json ----\n");
        }else{
            printf("---- open err.json failed----\n");
        }

        printf("--- on_Log tid=%ld event_type=%d\n\n",hv_gettid(),(int)ev->event_type);

        //类型转换
        auto userdata = ((std::vector<uint8_t>*)(ev->userdata));
        if(errlog.is_open()){
            json err = json::from_bson(*userdata);
            errlog << std::setw(3)<< err << std::endl;
        }else{
            printf("errlog is not opened\n");
        }
        //回收
        delete(userdata);
        errlog.close();
    }

    static std::ofstream errlog;
};
std::ofstream JLog::errlog ;//静态成员初始化
#endif